package san

import (
	b "code.google.com/p/gochess/board"
	pos "code.google.com/p/gochess/position"
	"fmt"
)

var rank2Notation = map[b.Rank]string{
	b.Rank1: "1",
	b.Rank2: "2",
	b.Rank3: "3",
	b.Rank4: "4",
	b.Rank5: "5",
	b.Rank6: "6",
	b.Rank7: "7",
	b.Rank8: "8",
}

func sprintRank(sq b.Square) string {
	return rank2Notation[b.GetRank(sq)]
}

var file2Notation = map[b.File]string{
	b.A: "a",
	b.B: "b",
	b.C: "c",
	b.D: "d",
	b.E: "e",
	b.F: "f",
	b.G: "g",
	b.H: "h",
}

func sprintFile(sq b.Square) string {
	return file2Notation[b.GetFile(sq)]
}

func SprintSquare(sq b.Square) string {
	return sprintFile(sq) + sprintRank(sq)

}

var pieceType2Notation = map[pos.PieceType]string{
	pos.NoPieceType: "",
	pos.King:        "K",
	pos.Queen:       "Q",
	pos.Rook:        "R",
	pos.Bishop:      "B",
	pos.Knight:      "N",
}

func SprintPiece(piece pos.PieceType) string {
	return pieceType2Notation[piece]
}

var castling2Notation = map[pos.CastlingOption]string{
	pos.CastlingShort: "0-0",
	pos.CastlingLong:  "0-0-0",
}

// check "+" will not be printed. According to the FIDE rules this is ok.
func SprintMove(p *pos.Position, move pos.Move, validMoves []pos.Move) string {

	// first handle castlings
	if move.Castling() != pos.NoCastling {
		return castling2Notation[move.Castling()]
	}
	dst := SprintSquare(move.Destination())
	if move.Destination() == p.EnPassantTarget() {
		// en passant capture
		return fmt.Sprint(sprintFile(move.Start()), capture, dst, enPassant)
	}
	var sep, start string
	if p.Get(move.Destination()) != pos.NoPiece {
		// we have a capture
		sep = capture
	}
	if p.Get(move.Start()).Type() == pos.Pawn {
		// pawn moves
		if p.Get(move.Destination()) != pos.NoPiece {
			// if a pawn captures print departure file
			start = sprintFile(move.Start())
		}
		return fmt.Sprint(start, sep, dst, SprintPiece(move.Promotion()))
	}
	moves := findMoves(p.Get(move.Start()).Type(), move.Destination(),
		p, validMoves)
	if len(moves) == 1 {
		return fmt.Sprint(SprintPiece(p.Get(move.Start()).Type()), start, sep, dst)
	}
	// more than two pieces of the same type can reach the destination
	// find out what info we have to print for the departure square

	// first count pieces sharing the same rank/file with the mover
	var rank, file int
	for i := range moves {
		if b.GetFile(move.Start()) == b.GetFile(moves[i].Start()) {
			file++
		}
		if b.GetRank(move.Start()) == b.GetRank(moves[i].Start()) {
			rank++
		}
	}
	// find out what we have to print
	if rank > 1 {
		if file > 1 {
			start = SprintSquare(move.Start())
		} else {
			start = sprintFile(move.Start())
		}
	} else {
		if file > 1 {
			start = sprintRank(move.Start())
		} else {
			start = sprintFile(move.Start())
		}
	}
	return fmt.Sprint(SprintPiece(p.Get(move.Start()).Type()), start, sep, dst)
}
